
function earthInstance(mapContainerId, onInitialize, settings) {

	var ge;
	var speed = 4; // degrees/second 
	var lastFrameTs  = (new Date()).getTime(); //last frame's timestamp 


	var init=function(kmlUrl) {
		if (typeof(google) == 'undefined' || !google.earth.isSupported()) {
			var errHtml = "<div id='plugin-custom-error'><p style='text-align: center;'>Google Earth plugin is not compatible with this browser. Please, make sure you are running a Chrome/Firefox/Safari browser in a Windows or Mac machine.<\/p>";
			$('#'+mapContainerId).html(errHtml);
			onInitialize(false);
		} else if (!google.earth.isInstalled()) {
			var errHtml = "<div id='plugin-custom-error'><p style='text-align: center;'>Google Earth plugin is not installed. Please, install it to see the 3D map here.<\/div>";
			$('#'+mapContainerId).html(errHtml);
			onInitialize(false);
		} else if (google.earth.isInstalled()) {
			google.earth.createInstance(mapContainerId, 
				function(instance) {
						initCB(instance); 
						if (kmlUrl) {
							google.earth.fetchKml(instance, kmlUrl, function(kmlObject) {
								if (kmlObject) instance.getFeatures().appendChild(kmlObject);
								onInitialize(true, instance);
							}) 
						} else {
							onInitialize(true, instance);
						}

				}, function(errorCode) {
						failureCB(errorCode);
						onInitialize(false);
				});
		}
	};


	var initCB=function(instance) {
	   ge = instance;
	   ge.getNavigationControl().setVisibility(ge.VISIBILITY_HIDE);
	   ge.getOptions().setFlyToSpeed(settings.flyToSpeed || ge.SPEED_TELEPORT); 
	   ge.getOptions().setMouseNavigationEnabled(settings.mouseNavigation || false); 
	   ge.getOptions().setFadeInOutEnabled(false);
	   ge.getOptions().setAtmosphereVisibility(true);
	   setInitialView(ge);
	   ge.getWindow().setVisibility(true);
	   if (settings.spin || false) google.earth.addEventListener(ge, "frameend", function() {setTimeout(spin, 50);}); 
	};

	var failureCB=function(errorCode) {
	  window.alert("Oops, could not load Google Earth: "+errorCode);
	};

	var setInitialView=settings.initialView || function() {
	  var cam = ge.getView().copyAsCamera(ge.ALTITUDE_ABSOLUTE);
		cam.setAltitude(8100000);
		ge.getView().setAbstractView(cam);
	};

	var spin=function() {
	   var nowTs = (new Date()).getTime();  //currrent timestamp 
	   if (timeDirection==0) {
		 lastFrameTs=nowTs+500;
		 return;
	   }
	   var dt = nowTs - lastFrameTs ; //delta time 
	   lastFrameTs  = nowTs; 
	   var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_ABSOLUTE); 
	   var distance = dt * (speed/500); //distance to rotate 
	   var newLongitude = lookAt.getLongitude() + distance*timeDirection;
	   if (newLongitude>=180.0) newLongitude=-179.999;
	   if (newLongitude<=-180.0) newLongitude=179.999;
	   lookAt.setLongitude(newLongitude); 
	   ge.getView().setAbstractView(lookAt); 
	} ;

	var removePoint=function(id) {
	  if (typeof(google)=='undefined' || !google.earth.isInstalled()) {
		return;
	  }
	  var obj=ge.getElementById('chapter'+id);
	  if (obj) {
		ge.getFeatures().removeChild(obj);
		obj.release();
	  }
	};

	var addPoint=function(coords) {
	  if (typeof(google)=='undefined' || !google.earth.isInstalled() || !ge) {
		return;
	  }
		// Create the placemark.
		var polygonPlacemark = ge.createPlacemark('chapter'+coords.id);

		// Create the polygon.
		var polygon = ge.createPolygon('');
		polygon.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
		polygon.setExtrude(true);
		polygonPlacemark.setGeometry(polygon);

		// Add points for the outer shape.
		var outer = ge.createLinearRing('');
		outer.setExtrude(true);
		outer.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
		outer.getCoordinates().pushLatLngAlt(coords.lat-0.1, coords.lon-0.1, 595000);
		outer.getCoordinates().pushLatLngAlt(coords.lat-0.1, coords.lon+0.1, 595000);
		outer.getCoordinates().pushLatLngAlt(coords.lat+0.1, coords.lon+0.1, 595000);
		outer.getCoordinates().pushLatLngAlt(coords.lat+0.1, coords.lon-0.1, 595000);
		polygon.setOuterBoundary(outer);

		//Create a style and set width and color of line
		polygonPlacemark.setStyleSelector(ge.createStyle(''));
		var lineStyle = polygonPlacemark.getStyleSelector().getLineStyle();
		lineStyle.setWidth(1);
		lineStyle.getColor().set('ffffffff');

		// Add the placemark to Earth.
		ge.getFeatures().appendChild(polygonPlacemark);
	};

	
	return {getGe: function() {return ge;},  init: init, addPoint: addPoint, removePoint: removePoint};
}

var smallEarth=earthInstance("map3d", function() { timeDirection=1;}, {spin: true});
if (typeof(google)!='undefined') {
  google.load("earth", "1");
  google.setOnLoadCallback(function() {smallEarth.init();});
} else {
  smallEarth.init();
}
